package com.ht.WeNas.service;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ht.WeNas.dao.repo.FileBucketDataRepo;
import com.ht.WeNas.dao.repo.FileBucketInfoRepo;
import com.ht.WeNas.data.dto.FbData;
import com.ht.WeNas.data.entity.FbInfo;
import com.ht.WeNas.data.vo.ResPage;
import com.ht.WeNas.utils.FileAccessUtils;
import com.ht.WeNas.utils.MyIdUtil;
import com.ht.WeNas.utils.MyPathUtil;
import com.ht.WeNas.utils.exceptions.MessageException;
import jakarta.annotation.Nullable;
import org.springframework.stereotype.Service;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

@Service
public class FileBucketService {
    private final FileBucketInfoRepo fileBucketInfoRepo;
    private final FileBucketDataRepo fileBucketDataRepo;

    public FileBucketService(FileBucketInfoRepo fileBucketInfoRepo, FileBucketDataRepo fileBucketDataRepo) {
        this.fileBucketInfoRepo = fileBucketInfoRepo;
        this.fileBucketDataRepo = fileBucketDataRepo;
    }

    /**
     * 创建文件容器
     *
     * @param name 容器名称
     * @param path 容器路径
     */
    public void createFileBucket(String name, String path) {
        if (StrUtil.isBlank(name) || StrUtil.isBlank(path)) {
            throw new MessageException("名称或路径为空");
        }
        if (!Files.isDirectory(Path.of(path))) {
            return;
        }
        FbInfo fbInfo = new FbInfo();
        fbInfo.setId(MyIdUtil.nextId());
        fbInfo.setAvailable(true);
        fbInfo.setName(name);
        fbInfo.setRootPath(path.replaceAll("\\\\", "/"));
        fbInfo.setType("default");
        fileBucketInfoRepo.save(fbInfo);
    }
    
    /**
     * 分页获取容器信息
     * @param pageSize 单页大小
     * @param pageCurrent 页码
     * @param search 查询参数
     * @return 查询到的容器信息
     */
    public Page<FbInfo> pageFbInfo(long pageSize, long pageCurrent, @Nullable String search, @Nullable String type) {
        LambdaQueryWrapper<FbInfo> wrapper = Wrappers.lambdaQuery(FbInfo.class);
        if (StrUtil.isNotBlank(search)) {
            wrapper.like(FbInfo::getName, wrapper);
            wrapper.or();
            wrapper.like(FbInfo::getRootPath, wrapper);
        }
        if (StrUtil.isNotBlank(type)) {
            wrapper.eq(FbInfo::getType, type);
        }
        return fileBucketInfoRepo.page(new Page<>(pageCurrent, pageSize), wrapper);
    }

    /**
     * 分页获取容器中的所有文件
     * @param id 容器id
     * @param size 分页大小
     * @param current 页码
     * @param contentTypePrefix 查找特定文件类型
     * @return 分页结果
     */
    public ResPage<Path> pageFileById(long id, int current, int size, String contentTypePrefix) {
        List<Path> fileList = loadFiles(id);
        if (!StrUtil.isBlank(contentTypePrefix)) {
            fileList = fileList.stream()
                    .filter(path -> MyPathUtil.contentTypeFilter(path, contentTypePrefix))
                    .toList();
        }
        return ResPage.fromList(current, size, fileList);
    }

    /**
     * 根据id获取容器信息
     * @param id 文件容器id
     * @return 容器信息
     */
    public FbInfo getFbInfoById(long id) {
        return fileBucketInfoRepo.getById(id);
    }

    /**
     * 根据id删除文件容器
     *
     * @param id 文件容器id
     */
    public void deleteById(long id) {
        fileBucketInfoRepo.removeById(id);
        fileBucketDataRepo.dropById(id);
    }

    /**
     * 分页获取容器所有文件夹
     * @param id 文件容器id
     * @param current 页码
     * @param size 单页大小
     * @return 所有文件夹分页对象
     */
    public ResPage<Path> pageDirById(long id, int current, int size) {
        return ResPage.fromList(current, size, this.loadDirs(id));
    }

    /**
     * 分页指定容器的指定文件夹
     * @param id 文件容器id
     * @param dirPath 文件夹路径
     * @param current 页码
     * @param size 单页大小
     * @param contentTypePrefix 限定文件类型前缀
     * @return 指定文件夹中的分页对象
     */
    public ResPage<Path> pageFileInDirById(long id, String dirPath, int current, int size, @Nullable String contentTypePrefix) {
        List<FbData> load = 
                fileBucketDataRepo.load(id, (i) -> 
                        FileAccessUtils.listFiles(Path.of(fileBucketInfoRepo.getById(i).getRootPath())));
        Path path = Path.of(dirPath);
        for (FbData data : load) {
            if (data.getDir().equals(path)) {
                List<Path> fileList = data.getFileList();
                if (StrUtil.isNotBlank(contentTypePrefix)) {
                    fileList = fileList.stream().filter(p -> MyPathUtil.contentTypeFilter(p, contentTypePrefix)).toList();
                }
                return ResPage.fromList(current, size, fileList);
            }
        }
        return new ResPage<>(current, size, 0);
    }

    public List<Path> listFileInDirById(long id, String dirPath) {
        List<FbData> load =
                fileBucketDataRepo.load(id, (i) ->
                        FileAccessUtils.listFiles(Path.of(fileBucketInfoRepo.getById(i).getRootPath())));
        Path path = Path.of(dirPath);
        for (FbData data : load) {
            if (data.getDir().equals(path)) {
                return data.getFileList();
            }
        }
        return List.of();
    }
    
    /**
     * 根据id更新容器信息
     * @param fbInfo 新容器信息
     */
    public void updateFileBucketInfo(FbInfo fbInfo) {
        if (fbInfo.getId() == null) {
            throw new MessageException("参数错误，更新失败");
        }
        fileBucketInfoRepo.updateById(fbInfo);
        fileBucketDataRepo.dropById(fbInfo.getId());
    }

    /**
     * 读取容器内的文件夹
     * @param id 容器id
     * @return 所有文件夹
     */
    public List<Path> loadDirs(Long id) {
        List<FbData> pairList = fileBucketDataRepo.load(
                id, (_id) -> FileAccessUtils.listFiles(Path.of(fileBucketInfoRepo.getById(_id).getRootPath()))
        );
        return pairList.stream().map(FbData::getDir).toList();
    }

    /**
     * 读取容器内的文件
     * @param id 容器id
     * @return 所有文件
     */
    public List<Path> loadFiles(Long id) {
        List<FbData> pairList = fileBucketDataRepo.load(
                id, (_id) -> FileAccessUtils.listFiles(Path.of(fileBucketInfoRepo.getById(_id).getRootPath()))
        );
        return pairList.stream().flatMap(item -> item.getFileList().stream()).toList();
    }
}
